package com.example.threadmodel.model;

import com.example.threadmodel.service.ThreadManagerService;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.*;

@Slf4j
public class Action<V> implements Callable<V> {
    @Getter
    protected String actionUid;

    // 当前Action入的哪个队列,因为在执行完毕后，需要取下一个任务!!!
    @Setter
    private ActionQueue actionQueue;

    // 队列中的任务, 用Callable这样子可以拿到执行结果
    protected Callable<V> actCallable;

    // 保证在submitAction时进入了线程池中
    private final CountDownLatch waitSetFutureLatch = new CountDownLatch(1); // 等待设置上Future

    // 为了执行同步的拿结果,因此需要设置上Future，在提交到线程池中的时候，得到Future并设置上, 提交到线程池了才放开，这样子get时，没有提交到线程池会一直阻塞那
    private volatile Future<V> future;

    // 任务执行异常
    private Exception runException;

    private long toQueueTime = System.currentTimeMillis();

    public Action(String actionUid, Callable<V> actCallable) {
        this.actionUid = actionUid;
        this.actCallable = actCallable;
    }

    @Override
    public V call() throws Exception {
        V result = null;
        try {
            // 执行拿到结果
            result = actCall();

            // 耗时!!! 这一步轮到执行，竟然花了那么久!!!
            //log.error("action run finish uid:{}, threadName:{}, costTime:{}", actionUid, Thread.currentThread().getName() , System.currentTimeMillis() - toQueueTime);
        } catch (Exception e) {
            runException = e;
            log.error("Exception!! Action run exception. actionUid:{}, error=", actionUid, e);
        } finally {
            actionQueue.submitNextAction(); // 一个任务执行完毕，接着执行下一个任务
        }

        return result;
    }

    public V actCall() throws Exception {
        return actCallable.call();
    }

    /**
     * 同步获取结果
     *
     * @return
     */
    public V get() {
        // 队列套队列，会完蛋!!!
        if (Thread.currentThread().getName().startsWith(ThreadManagerService.ACTION_THREAD_NAME_PREFIX)) {
            // 当前线程是ActionManager的工作线程,则不能进行这种get
            throw new ActionProhibitGetException();
        }

        V result = null;
        try {
            waitSetFutureLatch.await();
            result = future.get();
            if (runException != null) {
                RuntimeException runtimeException = new RuntimeException();
                runtimeException.addSuppressed(runException);
                throw runtimeException;
            }
        } catch (Throwable e) {
            RuntimeException runtimeException = new RuntimeException();
            runtimeException.addSuppressed(e);
            throw runtimeException;
        }

        return result;
    }

    /**
     * 支持等待超时
     *
     * @param timeOut
     * @return
     * @throws Exception
     */
    public V get(int timeOut) throws Exception {
        if (Thread.currentThread().getName().startsWith(ThreadManagerService.ACTION_THREAD_NAME_PREFIX)) {
            // 当前线程是ActionManager的工作线程,则不能进行这种get
            throw new ActionProhibitGetException();
        }
        boolean awaitSuccess = waitSetFutureLatch.await(timeOut, TimeUnit.MILLISECONDS);

        // 超时了!!!
        if (!awaitSuccess) {
            throw new TimeoutException();
        }

        V result = future.get(timeOut, TimeUnit.MILLISECONDS);

        if (runException != null) {
            throw runException;
        }
        return result;
    }

    public void setFuture(Future<V> future) {
        this.future = future;
        this.waitSetFutureLatch.countDown();
    }
}

















